package mnfstedit

import (
	_ "embed"
	"os"
	"reflect"
	"io/ioutil"
	"path/filepath"
	"kumachan/standalone/qt"
	"kumachan/standalone/util"
	"kumachan/standalone/util/opensave"
	"kumachan/interpreter/compiler/loader/manifest"
)


//go:embed mnfstedit.ui
var uiDefXml string
type editorWindow struct {
	Window   qt.MainWindow
	Widgets  editorWindowChildObjects
}
type editorWindowChildObjects struct {
	New   qt.Action
	Open  qt.Action
	Save  qt.Action
	CurrentEditing  qt.Label
	UniqueId        qt.LineEdit
	Description     qt.PlainTextEdit
	Dependencies    qt.TreeWidget
	DependencyAdd     qt.PushButton
	DependencyRemove  qt.PushButton
	DependencyDown    qt.PushButton
	DependencyUp      qt.PushButton
	Dependency  qt.GroupBox
	ImportName  qt.LineEdit
	ModulePath  qt.LineEdit
	Browse      qt.PushButton
}
const ManifestFileFilter = "KumaChan Module Manifest (*.kmmm)"

func Setup() {
	var ui editorWindow
	var err = qt.LoadWidget(uiDefXml, util.ExeDir(), func(root qt.Widget) error {
		var err1 = root.ExactlyAssignTo(reflect.ValueOf(&ui.Window))
		if err1 != nil { return err1 }
		var err2 = root.ExactlyAssignChildrenTo(reflect.ValueOf(&ui.Widgets))
		if err2 != nil { return err2 }
		return nil
	})
	if err != nil { panic(err) }
	var e = opensave.NewSingletonEditor("", func(state opensave.EditingState) {
		var current_editing string
		switch state.Status {
		case opensave.Idle:
			current_editing = "(empty)"
		case opensave.NewDoc:
			current_editing = "(new)"
		case opensave.Dirty:
			current_editing = ("[*] " + state.FilePath)
		case opensave.Clean:
			current_editing = state.FilePath
		}
		ui.Widgets.CurrentEditing.SetText(current_editing)
	})
	var mod, deps = newModule(e.NotifyMutation)
	var load = func(data manifest.Module) {
		mod.Init(data, func(data manifest.Module) {
			ui.Widgets.UniqueId.SetText(data.UniqueId)
			ui.Widgets.Description.SetText(data.Description)
			ui.Widgets.Dependencies.SetItems(deps.TreeItems())
		})
	}
	ui.Widgets.UniqueId.WatchText(func(value string) {
		mod.Mutate(func(data *manifest.Module) {
			data.UniqueId = value
		})
	})
	ui.Widgets.Description.WatchText(func(value string) {
		mod.Mutate(func(data *manifest.Module) {
			data.Description = value
		})
	})
	ui.Widgets.Dependencies.WatchCurrentItemKey(func(key string, exists bool) {
		var item, exists_ = deps.SetCurrent(key, exists)
		if exists_ {
			ui.Widgets.ImportName.SetText(item.ImportName)
			ui.Widgets.ModulePath.SetText(item.ModulePath)
			ui.Widgets.ImportName.SetEnabled(true)
			ui.Widgets.ModulePath.SetEnabled(true)
			ui.Widgets.Browse.SetEnabled(true)
			ui.Widgets.DependencyRemove.SetEnabled(true)
			ui.Widgets.DependencyDown.SetEnabled(true)
			ui.Widgets.DependencyUp.SetEnabled(true)
		} else {
			ui.Widgets.ImportName.SetText("")
			ui.Widgets.ModulePath.SetText("")
			ui.Widgets.ImportName.SetEnabled(false)
			ui.Widgets.ModulePath.SetEnabled(false)
			ui.Widgets.Browse.SetEnabled(false)
			ui.Widgets.DependencyRemove.SetEnabled(false)
			ui.Widgets.DependencyDown.SetEnabled(false)
			ui.Widgets.DependencyUp.SetEnabled(false)
		}
	})
	ui.Widgets.DependencyAdd.OnClick(func() {
		var empty = manifest.Dependency {}
		ui.Widgets.Dependencies.SetItems(deps.Append(empty))
	})
	ui.Widgets.DependencyRemove.OnClick(func() {
		ui.Widgets.Dependencies.SetItems(deps.RemoveCurrent())
	})
	ui.Widgets.DependencyDown.OnClick(func() {
		ui.Widgets.Dependencies.SetItems(deps.AdjustDownCurrent())
	})
	ui.Widgets.DependencyUp.OnClick(func() {
		ui.Widgets.Dependencies.SetItems(deps.AdjustUpCurrent())
	})
	ui.Widgets.ImportName.WatchText(func(value string) {
		ui.Widgets.Dependencies.SetItems(deps.UpdateCurrent(func(item *manifest.Dependency) {
			item.ImportName = value
		}))
	})
	ui.Widgets.ModulePath.WatchText(func(value string) {
		ui.Widgets.Dependencies.SetItems(deps.UpdateCurrent(func(item *manifest.Dependency) {
			item.ModulePath = value
		}))
	})
	ui.Widgets.Browse.OnClick(func() {
		var base_dir = e.BaseDir()
		var dir = qt.FileDialogSelectDirectory(ui.Window.Widget, qt.FileDialogOptions {
			Title: "Select Dependency Module",
			Cwd:   base_dir,
		})
		if dir == "" {
			return
		}
		var value, err = filepath.Rel(base_dir, dir)
		if err != nil { value = dir }
		ui.Widgets.ModulePath.SetTextWithSignal(value)
	})
	var discard_confirm = func() bool {
		return qt.MessageBoxConfirm (
			ui.Window.Widget,
			"Confirm", "Discard changes?",
		)
	}
	var show_error = func(err error) {
		qt.MessageBoxError (
			ui.Window.Widget,
			"Error", err.Error(),
		)
	}
	ui.Widgets.New.OnTrigger(func() {
		e.New(discard_confirm, func() {
			load(manifest.Module {})
		})
	})
	ui.Widgets.Open.OnTrigger(func() {
		var err = e.Open(discard_confirm, func() (string, bool, error) {
			var path = qt.FileDialogOpen(ui.Window.Widget, qt.FileDialogOptions {
				Title:  "Open Manifest File",
				Cwd:    e.BaseDir(),
				Filter: ManifestFileFilter,
			})
			if path == "" { return "", false, nil }
			var content, err1 = ioutil.ReadFile(path)
			if err1 != nil { return "", false, err1 }
			var data, err2 = manifest.Load(content)
			if err2 != nil { return "", false, err2 }
			load(data)
			return path, true, nil
		})
		if err != nil {
			show_error(err)
		}
	})
	ui.Widgets.Save.OnTrigger(func() {
		var err = e.Save(func() (string, bool) {
			var path = qt.FileDialogSave(ui.Window.Widget, qt.FileDialogOptions {
				Title:  "Save Manifest File",
				Cwd:    e.BaseDir(),
				Filter: ManifestFileFilter,
			})
			if path == "" { return "", false }
			return path, true
		}, func(path string) error {
			var data = mod.Get()
			var content = manifest.Store(data)
			return ioutil.WriteFile(path, content, 0o644)
		})
		if err != nil {
			show_error(err)
		}
	})
	ui.Window.OnClose(func() {
		e.Quit(discard_confirm, func() {
			os.Exit(0)
		})
	})
	qt.CommitTask(func() {
		e.Refresh()
		ui.Window.MoveToScreenCenter()
		ui.Window.Show()
	})
}


